package com.hsjk.szwj.module.pay.service.payway;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.hsjk.szwj.framework.common.exception.ServiceException;
import com.hsjk.szwj.framework.common.exception.enums.GlobalErrorCodeConstants;
import com.hsjk.szwj.module.pay.controller.app.order.vo.UnifiedOrderReqVO;
import com.hsjk.szwj.module.pay.controller.app.order.vo.WxJsapiOrderReqVO;
import com.hsjk.szwj.module.pay.controller.app.order.vo.WxJsapiOrderRespVO;
import com.hsjk.szwj.module.pay.dal.dataobject.config.AbstractResp;
import com.hsjk.szwj.module.pay.dal.dataobject.config.ChannelRetMsg;
import com.hsjk.szwj.module.pay.dal.dataobject.config.MchAppConfigContext;
import com.hsjk.szwj.module.pay.dal.dataobject.config.WxServiceWrapper;
import com.hsjk.szwj.module.pay.dal.dataobject.order.PayOrderDO;
import com.hsjk.szwj.module.pay.service.PayInterfaceDefineService;
import com.hsjk.szwj.module.pay.service.WxpayPaymentService;
import com.hsjk.szwj.module.pay.util.ApiResBuilder;
import com.hsjk.szwj.module.pay.util.WxpayKit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author chenjiawei
 * @desc 微信 jsapi支付
 * @Date 2023/08/27 23:46
 **/
@Service("plspayPaymentByWxJsapiService") //Service Name需保持全局唯一性
@Slf4j
public class WxJsapi extends WxpayPaymentService {

    @Resource
    private PayInterfaceDefineService payInterfaceDefineService;

    @Override
    public String preCheck(UnifiedOrderReqVO rq, PayOrderDO payOrder) {
        WxJsapiOrderReqVO bizRQ = new WxJsapiOrderReqVO();
        BeanUtils.copyProperties(rq, bizRQ);
        if (StringUtils.isEmpty(bizRQ.getOpenid())) {
            throw new ServiceException(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),
                    "[openid]不可为空");
        }
        return null;
    }

    @Override
    public AbstractResp pay(UnifiedOrderReqVO rq, PayOrderDO payOrder,
                            MchAppConfigContext mchAppConfigContext) throws Exception {
        WxJsapiOrderReqVO bizRQ = new WxJsapiOrderReqVO();
        BeanUtils.copyProperties(rq, bizRQ);

        WxPayUnifiedOrderRequest req = buildUnifiedOrderRequest(payOrder, mchAppConfigContext);
        req.setTradeType(WxPayConstants.TradeType.JSAPI);
        if (mchAppConfigContext.isIsvsubMch() && StringUtils.isNotBlank(req.getSubAppId())) {
            // 特约商户 && 传了子商户appId
            // 用户在子商户appid下的唯一标识
            req.setSubOpenid(bizRQ.getOpenid());
        } else {
            req.setOpenid(bizRQ.getOpenid());
        }

        // 构造函数响应数据
        WxJsapiOrderRespVO res = ApiResBuilder.buildSuccess(WxJsapiOrderRespVO.class);
        ChannelRetMsg channelRetMsg = new ChannelRetMsg();
        res.setChannelRetMsg(channelRetMsg);

        // 调起上游接口：
        // 1. 如果抛异常，则订单状态为： 生成状态，此时没有查单处理操作。 订单将超时关闭
        // 2. 接口调用成功， 后续异常需进行捕捉， 如果 逻辑代码出现异常则需要走完正常流程，此时订单状态为： 支付中， 需要查单处理。
        WxServiceWrapper wxServiceWrapper = configContextQueryService.getWxServiceWrapper(mchAppConfigContext);
        WxPayService wxPayService = wxServiceWrapper.getWxPayService();
        try {
            WxPayMpOrderResult payResult = wxPayService.createOrder(req);
            JSONObject resJSON = (JSONObject) JSON.toJSON(payResult);
            resJSON.put("package", payResult.getPackageValue());

            res.setPayInfo(resJSON.toJSONString());

            // 支付中
            channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.WAITING);

        } catch (WxPayException e) {
            log.error("WxPayException:", e);
            //明确失败
            channelRetMsg.setChannelState(ChannelRetMsg.ChannelState.CONFIRM_FAIL);
            WxpayKit.commonSetErrInfo(channelRetMsg, e);
        }

        return res;
    }
}
